package com.dynamic.mybatis.core.enums;

import com.dynamic.mybatis.core.toolkit.StringUtils;

import java.math.BigDecimal;
import java.sql.JDBCType;
import java.sql.Types;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @Description @see java.sql.JDBCType
 * @Author xs
 * @Date 2023/3/15 18:27
 */
public interface   Type {
     Set<String> NUMBER_TYPES = Stream.of(StandardType.TINYINT.type , StandardType.SMALLINT.type ,
            StandardType.INTEGER.type , StandardType.BIGINT.type
            , StandardType.FLOAT.type , StandardType.DOUBLE.type).collect(Collectors.toSet());

     Set<String> DATE_TIME_TYPES = Stream.of(StandardType.DATE.type , StandardType.TIME.type , StandardType.TIMESTAMP.type).collect(Collectors.toSet());

    int getJdbcType();
    String getType();
    BigDecimal getMin();
    BigDecimal getMax();
    BigDecimal getLength();

    enum  StandardType implements Type{
       /**
        * Identifies the generic SQL type {@code BIT}.
        */
       BIT(Types.BIT,"bit", BigDecimal.valueOf(0), BigDecimal.valueOf(1)),
       /**
        * Identifies the generic SQL type {@code TINYINT}.
        */
       TINYINT(Types.TINYINT,"byte", BigDecimal.valueOf(Byte.MIN_VALUE),BigDecimal.valueOf(Byte.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code SMALLINT}.
        */
       SMALLINT(Types.SMALLINT,"short",BigDecimal.valueOf(Short.MIN_VALUE),BigDecimal.valueOf(Short.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code INTEGER}.
        */
       INTEGER(Types.INTEGER,"int",BigDecimal.valueOf(Integer.MIN_VALUE),BigDecimal.valueOf(Integer.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code BIGINT}.
        */
       BIGINT(Types.BIGINT,"long",BigDecimal.valueOf(Long.MIN_VALUE),BigDecimal.valueOf(Long.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code FLOAT}.
        */
       FLOAT(Types.FLOAT,"float",BigDecimal.valueOf(Float.MIN_VALUE),BigDecimal.valueOf(Float.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code REAL}.
        */
       REAL(Types.REAL),
       /**
        * Identifies the generic SQL type {@code DOUBLE}.
        */
       DOUBLE(Types.DOUBLE,"double",BigDecimal.valueOf(Double.MIN_VALUE),BigDecimal.valueOf(Double.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code NUMERIC}.
        */
       NUMERIC(Types.NUMERIC),
       /**
        * Identifies the generic SQL type {@code DECIMAL}.
        */
       DECIMAL(Types.DECIMAL),
       /**
        * Identifies the generic SQL type {@code CHAR}.
        */
       CHAR(Types.CHAR,"byte", BigDecimal.valueOf(Byte.MIN_VALUE),BigDecimal.valueOf(Byte.MAX_VALUE)),
       /**
        * Identifies the generic SQL type {@code VARCHAR}.
        */
       VARCHAR(Types.VARCHAR,"string"),
       /**
        * Identifies the generic SQL type {@code LONGVARCHAR}.
        */
       LONGVARCHAR(Types.LONGVARCHAR,"string"),
       /**
        * Identifies the generic SQL type {@code DATE}.
        */
       DATE(Types.DATE,"date"),
       /**
        * Identifies the generic SQL type {@code TIME}.
        */
       TIME(Types.TIME,"time"),
       /**
        * Identifies the generic SQL type {@code TIMESTAMP}.
        */
       TIMESTAMP(Types.TIMESTAMP,"timestamp"),
       /**
        * Identifies the generic SQL type {@code BINARY}.
        */
       BINARY(Types.BINARY),
       /**
        * Identifies the generic SQL type {@code VARBINARY}.
        */
       VARBINARY(Types.VARBINARY),
       /**
        * Identifies the generic SQL type {@code LONGVARBINARY}.
        */
       LONGVARBINARY(Types.LONGVARBINARY),
       /**
        * Identifies the generic SQL value {@code NULL}.
        */
       NULL(Types.NULL),
       /**
        * Indicates that the SQL type
        * is database-specific and gets mapped to a Java object that can be
        * accessed via the methods getObject and setObject.
        */
       OTHER(Types.OTHER),
       /**
        * Indicates that the SQL type
        * is database-specific and gets mapped to a Java object that can be
        * accessed via the methods getObject and setObject.
        */
       JAVA_OBJECT(Types.JAVA_OBJECT),
       /**
        * Identifies the generic SQL type {@code DISTINCT}.
        */
       DISTINCT(Types.DISTINCT),
       /**
        * Identifies the generic SQL type {@code STRUCT}.
        */
       STRUCT(Types.STRUCT,"struct"),
       /**
        * Identifies the generic SQL type {@code ARRAY}.
        */
       ARRAY(Types.ARRAY,"array"),
       /**
        * Identifies the generic SQL type {@code BLOB}.
        */
       BLOB(Types.BLOB),
       /**
        * Identifies the generic SQL type {@code CLOB}.
        */
       CLOB(Types.CLOB),
       /**
        * Identifies the generic SQL type {@code REF}.
        */
       REF(Types.REF),
       /**
        * Identifies the generic SQL type {@code DATALINK}.
        */
       DATALINK(Types.DATALINK),
       /**
        * Identifies the generic SQL type {@code BOOLEAN}.
        */
       BOOLEAN(Types.BOOLEAN,"boolean"),

       /* JDBC 4.0 Types */

       /**
        * Identifies the SQL type {@code ROWID}.
        */
       ROWID(Types.ROWID),
       /**
        * Identifies the generic SQL type {@code NCHAR}.
        */
       NCHAR(Types.NCHAR),
       /**
        * Identifies the generic SQL type {@code NVARCHAR}.
        */
       NVARCHAR(Types.NVARCHAR),
       /**
        * Identifies the generic SQL type {@code LONGNVARCHAR}.
        */
       LONGNVARCHAR(Types.LONGNVARCHAR),
       /**
        * Identifies the generic SQL type {@code NCLOB}.
        */
       NCLOB(Types.NCLOB),
       /**
        * Identifies the generic SQL type {@code SQLXML}.
        */
       SQLXML(Types.SQLXML),

       /* JDBC 4.2 Types */

       /**
        * Identifies the generic SQL type {@code REF_CURSOR}.
        */
       REF_CURSOR(Types.REF_CURSOR),

       /**
        * Identifies the generic SQL type {@code TIME_WITH_TIMEZONE}.
        */
       TIME_WITH_TIMEZONE(Types.TIME_WITH_TIMEZONE),

       /**
        * Identifies the generic SQL type {@code TIMESTAMP_WITH_TIMEZONE}.
        */
       TIMESTAMP_WITH_TIMEZONE(Types.TIMESTAMP_WITH_TIMEZONE);
       ;

       StandardType(int jdbcType) {
           this.jdbcType = jdbcType;
       }

       StandardType(int jdbcType,String type) {
           this.jdbcType = jdbcType;
           this.type = type;
       }

       StandardType(int jdbcType, String type,BigDecimal min,BigDecimal max) {
           this.jdbcType = jdbcType;
           this.type = type;
           this.min = min;
           this.max = max;
       }

       public int jdbcType;
       public String type;
       public BigDecimal min;
       public BigDecimal max;
       public BigDecimal length;

        public int getJdbcType() {
            return jdbcType;
        }

        @Override
        public String getType() {
            return type;
        }

        @Override
        public BigDecimal getMin() {
            return min;
        }

        @Override
        public BigDecimal getMax() {
            return max;
        }

        @Override
        public BigDecimal getLength() {
            return length;
        }
    }



     static Type getType(JDBCType jdbcType){
        return getType(jdbcType.getVendorTypeNumber());
    }

     static Type getType(String type){
        if(StringUtils.isBlank(type)){
            return null;
        }
        for(StandardType t : Type.StandardType.values()){
            if(type.equalsIgnoreCase(t.type)){
                return t;
            }
        }
        return null;
    }

     static Type getType(int jdbcType){
        for(StandardType t : Type.StandardType.values()){
            if(t.jdbcType == jdbcType){
                return t;
            }
        }
        return null;
    }
}